﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace BlueRoseGames.Controls.Text
{
    public class PerspectiveTransform : Transform
    {
        #region DependencyProperties

        public static readonly DependencyProperty CameraXProperty = Register("CameraX", typeof(double), typeof(PerspectiveTransform), 0d);
        public double CameraX
        {
            get { return (double)GetValue(CameraXProperty); }
            set { SetValue(CameraXProperty, value); }
        }

        public static readonly DependencyProperty CameraYProperty = Register("CameraY", typeof(double), typeof(PerspectiveTransform), 0d);
        public double CameraY
        {
            get { return (double)GetValue(CameraYProperty); }
            set { SetValue(CameraYProperty, value); }
        }
        
        public static readonly DependencyProperty CameraZProperty = Register("CameraZ", typeof(double), typeof(PerspectiveTransform), 120d);
        public double CameraZ
        {
            get { return (double)GetValue(CameraZProperty); }
            set { SetValue(CameraZProperty, value); }
        }
        
        public static readonly DependencyProperty AngleXProperty = Register("AngleX", typeof(double), typeof(PerspectiveTransform), 0d);
        public double AngleX
        {
            get { return (double)GetValue(AngleXProperty); }
            set { SetValue(AngleXProperty, value); }
        }
        
        public static readonly DependencyProperty AngleYProperty = Register("AngleY", typeof(double), typeof(PerspectiveTransform), 0d);
        public double AngleY
        {
            get { return (double)GetValue(AngleYProperty); }
            set { SetValue(AngleYProperty, value); }
        }
        
        public static readonly DependencyProperty AngleZProperty = Register("AngleZ", typeof(double), typeof(PerspectiveTransform), 0d);
        public double AngleZ
        {
            get { return (double)GetValue(AngleZProperty); }
            set { SetValue(AngleZProperty, value); }
        }

        #endregion

        public override Point TransformPoint(Point p)
        {
            // Algorithm adapted from http://en.wikipedia.org/wiki/3D_projection
            double angleX = AngleX.ToRadians();
            double angleY = AngleY.ToRadians();
            double angleZ = AngleZ.ToRadians();

            double sinX = Math.Sin(angleX);
            double cosX = Math.Cos(angleX);
            double sinY = Math.Sin(angleY);
            double cosY = Math.Cos(angleY);
            double sinZ = Math.Sin(angleZ);
            double cosZ = Math.Cos(angleZ);

            double cameraX = this.CameraX;
            double cameraY = this.CameraY;
            double cameraZ = this.CameraZ;

            double offsetX = cameraX - p.X;
            double offsetY = cameraY - p.Y;
            double offsetZ = cameraZ;

            double aux1 = cosY * offsetZ + sinY * (sinZ * offsetY + cosZ * offsetX);
            double aux2 = cosZ * offsetY - sinZ * offsetX;

            double dX = cosY * (sinZ * offsetY + cosZ * offsetX) - sinY * offsetZ;
            double dY = sinX * aux1 + cosX * aux2;
            double dZ = cosX * aux1 - sinX * aux2;

            double w = cameraZ / dZ;

            Point ret = new Point();
            ret.X = cameraX - dX * w;
            ret.Y = cameraY - dY * w;
            return ret;
        }
    }

    public static class DoubleUtil
    {
        public static double ToRadians(this double degrees)
        {
            return (degrees * Math.PI) / 180d;
        }
    }
}
